package com.fdb.efp.console.api.rest.sed;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.disk.DiskFileItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import com.alibaba.fastjson.JSON;
import com.irdstudio.basic.framework.core.constant.ApplicationConstance;
import com.irdstudio.basic.framework.core.constant.ResponseData;
import com.irdstudio.basic.framework.core.util.StringUtil;
import com.irdstudio.basic.framework.core.util.TimeUtil;
import com.irdstudio.basic.framework.web.controller.AbstractController;
import com.irdstudio.efp.console.common.ExcelException;
import com.irdstudio.efp.console.service.facade.SOrgService;
import com.irdstudio.efp.console.service.facade.sed.STaxOrgMapService;
import com.irdstudio.efp.console.service.vo.SOrgVO;
import com.irdstudio.efp.console.service.vo.sed.STaxOrgMapExcelVO;
import com.irdstudio.efp.console.service.vo.sed.STaxOrgMapVO;
import com.irdstudio.efp.console.common.util.ExcelImportUtil;

/**
 * 风控-所属地市映射维护
 * TODO
 *
 * @author wanglihua
 * @version 1.0
 * @since 2019年4月25日 下午3:47:57
 */
@RestController
@RequestMapping("/api")
public class STaxOrgMapController extends AbstractController {

    @Autowired
    @Qualifier("sTaxOrgMapService")
    private STaxOrgMapService sTaxOrgMapService;

    @Autowired
    @Qualifier("sOrgService")
    private SOrgService sOrgService;

    private static final String CONTENTTYPE = "application/json;charset=UTF-8";

    private static final String MODELNAME = "所属地市映射导入模板.xls";

    private static final String IMPORT_PATH = "/template/importTemplate.xls";

    private List<STaxOrgMapExcelVO> singleRowList = new ArrayList<>();

    private List<STaxOrgMapExcelVO> sTaxOrgMapExcelVOList = new ArrayList<>();

    private List<STaxOrgMapExcelVO> errorHisDuplicateDataList = new ArrayList<>();

    /**
     * 分页查询
     */
    @RequestMapping(value = "/staxmap/infos", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<STaxOrgMapVO>> queryAllSTaxOrgMapByPage(@RequestBody STaxOrgMapVO inSTaxOrgMapVO) {
        List<STaxOrgMapVO> outputVo = sTaxOrgMapService.queryAllSTaxOrgMapByPage(inSTaxOrgMapVO);
        if (Objects.nonNull(outputVo)) addOrgNameToRs(outputVo);
        return getResponseData(outputVo);
    }

    private void addOrgNameToRs(List<STaxOrgMapVO> outputVo) {
        outputVo.forEach(item->{
            String orgCode = item.getOrgCode();
            SOrgVO sOrgVO = new SOrgVO();
            sOrgVO.setOrgCode(orgCode);
            SOrgVO queryRs = Optional.ofNullable(sOrgService.queryByPk(sOrgVO)).orElseGet(SOrgVO::new);
            item.setOrgName(queryRs.getOrgName());
        });
    }

    /**
     * 根据主键查询详情
     *
     * @return
     */
    @RequestMapping(value = "/staxmap/info/{orgCode}", method = RequestMethod.GET)
    public @ResponseBody
    ResponseData<STaxOrgMapVO> queryByPk(@PathVariable("prdId") String orgCode) {
        STaxOrgMapVO inVo = new STaxOrgMapVO();
        inVo.setOrgCode(orgCode);
        STaxOrgMapVO outputVo = sTaxOrgMapService.queryByPk(inVo);
        return getResponseData(outputVo);

    }

    /**
     * 根据主键删除信息
     *
     * @param orgCode
     * @return
     */
    @RequestMapping(value = "/staxmap/info", method = RequestMethod.DELETE)
    public @ResponseBody
    ResponseData<Integer> deleteByPk(@RequestBody STaxOrgMapVO inSTaxOrgMapVO) {
        int outputVo = sTaxOrgMapService.deleteByPk(inSTaxOrgMapVO);
        return getResponseData(outputVo);

    }

    /**
     * 根据主键更新信息
     *
     * @param
     * @return
     */
    @RequestMapping(value = "/staxmap/info", method = RequestMethod.PUT)
    public @ResponseBody
    ResponseData<Integer> updateByPk(@RequestBody STaxOrgMapVO inSTaxOrgMapVO) {
        int outputVo = sTaxOrgMapService.updateByPk(inSTaxOrgMapVO);
        return getResponseData(outputVo);

    }

    /**
     * 新增数据
     *
     * @param
     * @return
     */
    @RequestMapping(value = "/staxmap/info", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<Integer> insertPrdInfo(@RequestBody STaxOrgMapVO inSTaxOrgMapVO) {
        int outputVo = sTaxOrgMapService.insertSTaxOrgMap(inSTaxOrgMapVO);
        return getResponseData(outputVo);

    }

    /**
     * 导出数据
     *
     * @param
     * @return
     */
    @RequestMapping(value = "/staxmap/info/export", method = RequestMethod.POST)
    public @ResponseBody
    ResponseData<List<STaxOrgMapVO>> queryAllDataByCondition(@RequestBody STaxOrgMapVO inSTaxOrgMapVO) {
        List<STaxOrgMapVO> outputVo = sTaxOrgMapService.queryAllDataByCondition(inSTaxOrgMapVO);
        if (Objects.nonNull(outputVo)) addOrgNameToRs(outputVo);
        return getResponseData(outputVo);
    }

    /**
     * 模板下载
     *
     * @author
     * @version
     * @since
     */
    @RequestMapping(value = "/staxmap/info/downLoad", method = RequestMethod.GET)
    public @ResponseBody
    ResponseData<String> cusRelCherkModelDownLoad(HttpServletResponse response, HttpServletRequest request) throws IOException {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            response.setContentType(CONTENTTYPE);
            /**
             * getBytes()，需要声明一下读取的编码方式，不然IE浏览器，会出现文件名乱码，谷歌不会
             * 【解决方法】 getBytes("GBK")
             */
            response.setHeader("Content-Disposition", "attachment;filename=" + new String((MODELNAME).getBytes("GBK"), "ISO8859-1"));
            ServletOutputStream out = response.getOutputStream();
            logger.info("下载数据导入模板开始----------------------------");
            bis = new BufferedInputStream(STaxOrgMapController.class.getClassLoader().getResourceAsStream(IMPORT_PATH));
            bos = new BufferedOutputStream(out);
            byte[] buff = new byte[2048];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
        } catch (Exception e) {
            logger.error("模板文件下载失败：", e);
            return getResponseData(null);
        } finally {
            if (null != bis) {
                bis.close();
            }
            if (null != bos) {
                bos.close();
            }
        }
        logger.info("下载关联人数据导入模板结束。。。。。。。。。。。。。。。。。。。");
        return getResponseData("success!");
    }

    /**
     * 文件导入并解析储存到数据表
     *
     * @author
     * @version
     * @since
     */
    @SuppressWarnings("resource")
    @RequestMapping(value = "/staxmap/infos/upload", method = RequestMethod.POST)
    public void sTaxOrgMapUpload(HttpServletResponse respone, HttpServletRequest request) {
        ResponseData<List<STaxOrgMapVO>> result = new ResponseData<List<STaxOrgMapVO>>();
        List<File> sSTaxOrgMapChecks = new ArrayList<File>();
        respone.setContentType(CONTENTTYPE);
        OutputStream out = null;

        try {
            out = respone.getOutputStream();
            //获取文件
            sSTaxOrgMapChecks = getFileList(request);
            if (!sSTaxOrgMapChecks.isEmpty()) {
                for (File file : sSTaxOrgMapChecks) {
                    /**
                     * 将Excel文件解析成对应实体Bean
                     */
                    sTaxOrgMapExcelVOList.clear();
                    sTaxOrgMapExcelVOList = ExcelImportUtil.importExcelByClass(file, STaxOrgMapExcelVO.class);
                    //检查导入的数据是否填写重复
                    checkExcelDatas(sTaxOrgMapExcelVOList);
                    //检查历史数据是否重复
                    checkHisDatas(sTaxOrgMapExcelVOList);
                    //组装数据
                    List<STaxOrgMapVO> inserSTaxOrgMap = new ArrayList<STaxOrgMapVO>();
                    inserSTaxOrgMap = assembleData(sTaxOrgMapExcelVOList);
                    //执行插入操作
                    int num = execBatchInsertSql(inserSTaxOrgMap);
                    if (num < 0) {
                        throw new Exception("插入数据出错！请检查是否按照模板填写了正确的数据。");
                    }
                    //组装结果
                    result = getResponseData(inserSTaxOrgMap);
                }
            } else {
                throw new ExcelException("获取不到上传的文件！");
            }
        } catch (Exception e) {
            logger.error("文件上传失败,失败原因:", e);
            result = result.createData(null, ApplicationConstance.FAILURE, e.getMessage(), false);
        } finally {
            String str = JSON.toJSONString(result);
            try {
                out.write(str.getBytes(Charset.forName("UTF-8")));
                out.flush();
                out.close();
            } catch (IOException e) {
                logger.error("关闭数据流OutputStream出错，错误信息为：", e);
            }
        }
    }

    private List<STaxOrgMapVO> assembleData(List<STaxOrgMapExcelVO> sTaxOrgMapExcelVOList) throws ExcelException {
        List<STaxOrgMapVO> list = new ArrayList<>();
        if (Objects.nonNull(sTaxOrgMapExcelVOList)) {
            Iterator<STaxOrgMapExcelVO> iterator = sTaxOrgMapExcelVOList.iterator();
            while (iterator.hasNext()) {
                STaxOrgMapExcelVO tempExcelVO = iterator.next();

                STaxOrgMapVO tempVO = new STaxOrgMapVO();
                //分行机构码
                tempVO.setOrgCode(tempExcelVO.getOrgCode());
                //代扣代缴单位所属地市代码
                tempVO.setTaxAreaCode(tempExcelVO.getTaxAreaCode());
                //代扣代缴单位所属地市税局
                tempVO.setTaxAreaName(tempExcelVO.getTaxAreaName());
                //准入年收入
                tempVO.setAdIncomeY(tempExcelVO.getAdIncomeY());
                //系数
                tempVO.setCoefficient(tempExcelVO.getCoefficient());
                //创建人
                tempVO.setCreateUser(tempExcelVO.getCreateUser());
                //创建时间
                tempVO.setCreateTime(TimeUtil.getCurrentDateTime());
                //最后修改人
//				tempVO.setLastChgUser(tempExcelVO.getLastChgUser());
                //最后修改时间
//				tempVO.setLastChgTime(TimeUtil.getCurrentDateTime());
                list.add(tempVO);
            }
        } else {
            throw new ExcelException("获取数据为空!");
        }
        return list;
    }

    private void checkExcelDatas(List<STaxOrgMapExcelVO> sTaxOrgMapExcelVOList) throws Exception {
        int errorRow = 2;
        //地区代码为空
        List<Integer> errorNullRowList = new ArrayList<>();
        //excel数据填写重复
        List<Integer> errorExcelDuplicateList = new ArrayList<>();
        //
//        List<Integer> errorDuplicateList = new ArrayList<>();

        String errorNullMsg = "";
        String errorExcelDuplicateMsg = "";
//        String errorDuplicate = "";
        Map<Integer, String> errorList = new HashMap<Integer, String>();

        //统计excel表格里数据重复的“代扣代缴单位所属地市代码”
        List<String> excelDuplicateList = sTaxOrgMapExcelVOList.stream().filter(a -> !StringUtil.isNullorBank(a.getTaxAreaCode()))
                .collect(Collectors.groupingBy(a -> a.getTaxAreaCode(), Collectors.counting()))
                .entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .map(entry -> entry.getKey())
                .collect(Collectors.toList());

        for (STaxOrgMapExcelVO item : sTaxOrgMapExcelVOList) {
            //检查excel是否缺少关键字段
            if (StringUtil.isNullorBank(item.getTaxAreaCode())) {
                errorNullRowList.add(errorRow);
            }
            //找出重复的行
            if (excelDuplicateList.contains(item.getTaxAreaCode())) {
                errorExcelDuplicateList.add(errorRow);
            }
            errorRow += 1;
        }

//        List<Integer> tmp = new ArrayList<>();
//        tmp.addAll(errorDuplicateRowList);
        //在数据库已存在且excel填写重复的部分
//        errorDuplicateList = errorExcelDuplicateList.stream().filter(a -> tmp.contains(a)).collect(Collectors.toList());

//        List<Integer> tmp1 = new ArrayList<>();
//        tmp1.addAll(errorDuplicateList);
        //移除共同的数据
//        errorExcelDuplicateList = errorExcelDuplicateList.stream().filter(a -> !tmp1.contains(a)).collect(Collectors.toList());
//        errorDuplicateRowList = errorDuplicateRowList.stream().filter(a -> !tmp1.contains(a)).collect(Collectors.toList());

        if (errorNullRowList.size() > 0) {
            for (Integer integer : errorNullRowList) {
                errorNullMsg = "第【" + integer + "】行“代扣代缴单位所属地市代码”未填写！";
                logger.info("“代扣代缴单位所属地市代码”未填写：" + errorNullMsg);
                errorList.put(integer, errorNullMsg);
            }
        }

        if (errorExcelDuplicateList.size() > 0) {
            for (Integer integer : errorExcelDuplicateList) {
                errorExcelDuplicateMsg = "第【" + integer + "】行“代扣代缴单位所属地市代码”重复填写！";
                logger.info("“代扣代缴单位所属地市代码”重复填写：" + errorExcelDuplicateMsg);
                errorList.put(integer, errorExcelDuplicateMsg);
            }
        }
//        if (errorDuplicateList.size() > 0) {
//            for (Integer integer : errorDuplicateList) {
//                errorDuplicate = "第【" + integer + "】行“代扣代缴单位所属地市代码”重复填写，且存在历史数据！";
//                logger.info(errorDuplicate);
//                errorList.put(integer, errorDuplicate);
//            }
//        }

        //按key值对errorList排序并将value拼接成字符串
        String rs = "";
        rs += sortAndSpliceMap(errorList);
        if (!StringUtil.isNullorBank(rs)) {
            rs = "ExcelError:" + rs;
            throw new Exception(rs);
        }
    }

    private void checkHisDatas(List<STaxOrgMapExcelVO> sTaxOrgMapExcelVOList) throws Exception {
        int errorRow = 2;
        List<Integer> errorDuplicateRowList = new ArrayList<>();
        String errorDuplicateMsg = "";
        errorHisDuplicateDataList.clear();
        Map<Integer, String> errorList = new HashMap<Integer, String>();

        for (STaxOrgMapExcelVO item : sTaxOrgMapExcelVOList) {

            //检查数据是否在数据库已存在
            boolean flag = checkDataIsUnique(item);
            if (flag) {
                errorDuplicateRowList.add(errorRow);
                errorHisDuplicateDataList.add(item);
            }
            errorRow += 1;
        }

        //收集没问题的导入数据
        singleRowList.clear();
        singleRowList = sTaxOrgMapExcelVOList.stream().filter(a->!errorHisDuplicateDataList.contains(a)).collect(Collectors.toList());

        if (errorDuplicateRowList.size() > 0) {
            for (Integer integer : errorDuplicateRowList) {
                errorDuplicateMsg = "第【" + integer + "】行“代扣代缴单位所属地市代码”存在历史数据！";
                logger.info("已存在历史数据，重复的行：" + errorDuplicateMsg);
                errorList.put(integer, errorDuplicateMsg);
            }
        }

        //按key值对errorList排序并将value拼接成字符串
        String rs = "";
        rs += sortAndSpliceMap(errorList);
        if (!StringUtil.isNullorBank(rs)) {
            rs = "DataDuplicateError:" + rs;
            throw new Exception(rs);
        }
    }

    private String sortAndSpliceMap(Map<Integer, String> errorList) {
        String rs = "";
        //取出key值，根据key值排序
        Object[] key = errorList.keySet().toArray();
        Arrays.sort(key);
        //拼接信息
        Iterator ite = errorList.entrySet().iterator();
        while (ite.hasNext()) {
            Entry string = (Entry) ite.next();
            StringBuffer buffer = new StringBuffer();
            if (StringUtil.isNullorBank(rs)) {
                rs = (String) string.getValue();
            } else {
                rs = buffer.append(rs).append(",").append(string.getValue()).toString();
            }
        }
        return rs;
    }

    private boolean checkDataIsUnique(STaxOrgMapExcelVO item) {
        STaxOrgMapVO sTaxOrgMapVO = new STaxOrgMapVO();
        sTaxOrgMapVO.setTaxAreaCode(item.getTaxAreaCode());
        STaxOrgMapVO queryRs = null;
        try {
            queryRs = sTaxOrgMapService.queryByPk(sTaxOrgMapVO);
        } catch (Exception e) {
            logger.error("数据转化出错！" + e);
        }
        return Objects.isNull(queryRs) ? false : true;
    }

    /**
     * 从HttpServletRequest中获取文件
     *
     * @author
     * @version
     * @since
     */
    @SuppressWarnings("rawtypes")
    private List<File> getFileList(HttpServletRequest request) throws IOException {
        List<File> listFiles = new ArrayList<File>();
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(request.getSession().getServletContext());
        if (multipartResolver.isMultipart(request)) {
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
            Iterator iter = multiRequest.getFileNames();
            while (iter.hasNext()) {
                MultipartFile mFile = multiRequest.getFile(iter.next().toString());
                if (mFile != null) {
                    listFiles.add(multipartToFile(mFile));
                }
            }
        }
        return listFiles;
    }

    /**
     * 转换文件
     *
     * @author
     * @version
     * @since
     */
    private File multipartToFile(MultipartFile multfile) throws IOException {
        CommonsMultipartFile cmf = (CommonsMultipartFile) multfile;
        DiskFileItem dfi = (DiskFileItem) cmf.getFileItem();
        File file = dfi.getStoreLocation();
        if (file.length() < 2048) {
            File tmpFile = new File(System.getProperty("java.io.tmpdir") + System.getProperty("file.separator") + file.getName());
            multfile.transferTo(tmpFile);
            return tmpFile;
        }
        return file;
    }

    @RequestMapping(value="/staxmap/info/coverOrExclude/{flag}", method=RequestMethod.GET)
    public @ResponseBody ResponseData<Integer> coverOrExcludeDatas(@PathVariable("flag") String flag) throws Exception {
        int outputVo = 0;
        if (!"".equals(flag) && "cover".equals(flag)) {
            //删除重复的历史数据
            deleteDuplicateData(errorHisDuplicateDataList);
            //组装数据
            List<STaxOrgMapVO> inserSTaxOrgMap = new ArrayList<STaxOrgMapVO>();
            inserSTaxOrgMap = assembleData(sTaxOrgMapExcelVOList);
            //批量插入
            outputVo = execBatchInsertSql(inserSTaxOrgMap);
        }
        if (!"".equals(flag) && "exclude".equals(flag)) {
            //组装数据
            List<STaxOrgMapVO> inserSTaxOrgMap = new ArrayList<STaxOrgMapVO>();
            inserSTaxOrgMap = assembleData(singleRowList);
            //批量插入
            outputVo = execBatchInsertSql(inserSTaxOrgMap);
        }
        return getResponseData(outputVo);
    }

    private int execBatchInsertSql(List<STaxOrgMapVO> list) {
        int num = 0;
        return num = sTaxOrgMapService.batchInsert(list);
    }

    private void deleteDuplicateData(List<STaxOrgMapExcelVO> errorHisDuplicateDataList) {
        errorHisDuplicateDataList.forEach(item->{
            STaxOrgMapVO sTaxOrgMapVO = new STaxOrgMapVO();
            sTaxOrgMapVO.setTaxAreaCode(item.getTaxAreaCode());
            sTaxOrgMapService.deleteByPk(sTaxOrgMapVO);
        });
    }
}